import Color.*
import java.lang.StringBuilder
import java.util.*
import javax.print.attribute.IntegerSyntax
import kotlin.math.min

/**
 * 主方法
 */
//fun Function,方法(函数),代表当前是一个方法的修饰
//main 方法名,如果是main,则是主方法,程序的入口
//args 参数名,注意,kotlin中,参数名和类型是与java相反的,参数名在前,类型在后
//Array<String> String类型的数组,在kotlin当中,是没有[]这个概念的,所有的数组都是Array
//println 与java中System.out.println一样,是系统输出,省略了部分
//在kotlin当中,是不需要写分号的,但是要注意一行内,换行相当于分号

fun main(args: Array<String>) {
//    val a = 9
//    println("Hello,world")
//    println(max(6, 5))
////    array.add("Flutter")
//    println("Hello,${name}!")
//    println("1+2 = ${1 + 2}")
//    println("a ${if (a >= 10) "大于等于10" else "小于10"}")

//    val person = Person("lc", false) //构造不需要使用new的关键字
//    person.isMarried = true//相当于isMarried这属性的setter方法
//    println(person.name)//相当于调用name属性的getter方法
//    println(person.isMarried)//相当于调用IsMarried属性的getter方法
//
//    val rectangle = Rectangle(10, 10)
//    println(rectangle.height)
//    println(rectangle.width)
//    println(rectangle.isSquare)
//    println(getColorStr(BLUE))
//    println(mix(GREEN, YELLOW))

    //智能转换
    //is 相当于instanceof 也可以理解为是什么什么东西,比如例子中,a 是 dog,可以用 a is Dog 表示
    //is 检查一个变量是否是某种类型
    //as 意思是像,相当于强转
//    val a = Animal()
//    if (a is Dog) {
//        a.dig()
//    }
//
//    //as 为强转,
//    val dog = a as Dog
//    dog.dig()
    play()

}

/**
 * 方法(函数)
 */
//在kotlin当中所有的一行代码,都可以是一个表达式
//:Int代表当前方法的返回值,在kotlin中,所有的方法都是有返回值的,只是有的方法返回值为Unit,相当于在Java中的void
//如果有返回值的方法,可以转换为一个表达式,等号的形式
//在Kotlin中Int的声明必须是以大写字母开头

//fun max(a: Int, b: Int): Int {
//    return if (a > b) a else b
//}

fun max(a: Int, b: Int): Int = if (a > b) a else b

/**
 *  变量
 *  可变变量和不可变变量(常量)
 *  val (value) 不可变变量(常量).在初始化之后不能再次赋值,对应的是Java中的final修饰符
 *  var (variable) 可变变量.这种变量的值是可以被改变的,对应java中的普通变量
 *  两种变量的类型是可以不写的,在kotlin中可以通过赋值的类型,来决定变量的类型
 *  当初始化时类型被固定,再次赋值时,给出的值也必须符合
 *  如果使用val定义一个集合,与java相同,集合的内容是可变的
 */

val str: String = "这是一个String"

val array = arrayListOf("java", "kotlin")

var a = 12

/**
 * 字符串模板 在代码中声明一个name,可以加上$来进行使用,并且可以来进行计算和一些简单逻辑,与java中的数据绑定Xml里的操作类似
 */
val name = "lc"

/**
 * 类和属性
 * 包含了一个name的getName方法,因为name是final的,所有没有set方法
 * 类后面的括号就相当于这个类的构造方法,可以直接在其中声明变量或者常量
 */
class Person(val name: String,//只读属性,生成一个字段和一个简单的getter
             var isMarried: Boolean//可写属性,生成一个字段,一个getter,一个setter
)

//自定义访问器,如果getter和setter中需要额外的逻辑,可以通过自定义访问器实现
class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        //声明属性
        get() {//声明这个属性的getter方法
            return height == width
        }
}

/**
 * 表示和处理选择: 枚举和when
 *  在枚举类中,每个逗号都代表一个枚举的类型,如果在其中需要写方法,则要添加一个分号来分割
 */
enum class Color(val r: Int, val g: Int, val b: Int) {
    RED(255, 0, 0),
    ORANGE(255, 165, 0),
    YELLOW(255, 255, 0),
    GREEN(0, 255, 255),
    BLUE(0, 0, 255);

    fun rgb() =
            (r * 256 + g) * 256 + b
}

fun getColorStr(color: Color) =
        when (color) {
            RED, ORANGE, YELLOW -> "warm"
            GREEN -> "neutral"
            BLUE -> "cold"
        }

//set是集合一种,是无序的
fun mix(c1: Color, c2: Color) =
        when (setOf(c1, c2)) {
            setOf(RED, YELLOW) -> "ORANGE"
            setOf(YELLOW, BLUE) -> "GREEN"
            else -> throw Exception("我也不知道是什么颜色")
        }

//when可以不添加条件,可以直接在分支中进行判断
fun mixOpt(c1: Color, c2: Color) =
        when {
            (c1 == RED && c2 == YELLOW) || (c1 == YELLOW && c2 == RED) -> "ORANGE"
            (c1 == YELLOW && c2 == BLUE) || (c1 == BLUE && c2 == YELLOW) -> "GREEN"
            else -> throw Exception("我也不知道是什么颜色")
        }

/**
 * 循环
 * kotlin中,while do-while 循环和Java完全一致
 */

val oneToOne = 1..10 //1-10之间的整数
val oneToNine = 1 until 10//1-10之间但是不包括10的整数

fun fizzBuzz(i: Int) = when {
    i % 15 == 0 -> "FizzBuzz"
    i % 5 == 0 -> "Buzz"
    i % 3 == 0 -> "Fizz"
    else -> "$i"
}

//kotlin中,循环只有唯一一种存在形式,for <item> in <elements>
//downTo 倒数的意思,step 是步伐的意思,相当于隔1个数字
fun play() {
//    for (i in 100 downTo 1 step 2) {
//        println(fizzBuzz(i))
//    }

    val binaryReps = TreeMap<Char, String>()//使用TreeMap让键排序

    for (c in 'A'..'F') {//使用字符区间跌倒A到F之间的字符
        val binary = Integer.toBinaryString(c.toInt())//把ASCII码转换为二进制
        binaryReps[c] = binary  //根据键把对应的值存入map
    }

//    for ((letter, binary) in binaryReps) {
//        println("$letter = $binary")//循环时,letter代表map的key,binary代表map的value
//    }

//    val list = arrayListOf("10", "11", "1001")
//    for ((index, element) in list.withIndex()) {
//        println("$index,$element")
//    }
    //区间可以通过关键字 in 来检查一个元素是否在这个区间当中
//    println(check('ω'))
//    println(set.javaClass)
//    println(list.javaClass)
//    println(map.javaClass)

    val strings = listOf("first", "second", "fourteenth")
//    println(strings.last())
//    val numbers = setOf(1, 14, 2)
//    println(numbers.max())

    println(joinToString(strings, "|", "{", "}"))
}

fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'
fun isDigit(c: Char) = c in '0'..'9'

fun check(c: Char) = when (c) {
    in 'a'..'z', in 'A'..'Z' -> "这是一个字符"
    in '0'..'9' -> "这是一个数字"
    else -> "这可能是一个汉字"
}

/**
 * 集合
 */
val set = setOf(1, 2, 3)
val list = listOf(1, 2, 3)
val map = mapOf(1 to "one ", 2 to "two")

fun <T> joinToString(collection: Collection<T>,//需要修改的集合
                     separator: String, //分隔符
                     prefix: String, //在String头添加的字符
                     postfix: String//在String的尾添加的字符
): String {
    val result = StringBuilder(prefix)//生成一个String,并且在首位置添加头字符
    for ((index, element) in collection.withIndex()) { //进行迭代集合,取出所有集合中的元素
        if (index > 0) result.append(separator)//不在第一个元素的前面添加分隔符
        result.append(element)//把集合中的每一个元素都添加到StringBuilder中
    }
    result.append(postfix)//添加尾字符
    return result.toString()
}

